/* EasyWay Game Engine
 * Copyright (C) 2007 Daniele Paggi.
 *  
 * Written by: 2007 Daniele Paggi<dshnt@hotmail.com>
 *   
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 * 
 * You should have received a copy of the GNU Library General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package org.easyway.editor.forms;

import java.awt.Container;
import java.util.ArrayList;

import org.easyway.debug.DebugManager;
import org.easyway.editor.analyzer.Analyzer;
import org.easyway.editor.commands.CommandList;
import org.easyway.input.Keyboard;
import org.easyway.input.Mouse;
import org.easyway.interfaces.base.IDestroyable;
import org.easyway.interfaces.base.IList;
import org.easyway.interfaces.base.IType;
import org.easyway.interfaces.extended.ILayer;
import org.easyway.interfaces.sprites.IMaskerable;
import org.easyway.interfaces.sprites.IPlain2D;
import org.easyway.objects.Camera;
import org.easyway.objects.Plain2D;
import org.easyway.objects.Type;
import org.easyway.objects.sprites2D.Mask;
import org.easyway.system.Core;
import org.easyway.system.StaticRef;
import org.easyway.system.state.OpenGLState;
import org.lwjgl.opengl.GL11;

public class EditorCore extends Core {

	private static final long serialVersionUID = -8805238930427486640L;

	/**
	 * indicates if the grid is to draw or not 
	 */
	public static boolean drawGrid = true;

	/**
	 * indicates if the objects can be moved or not
	 */
	public static boolean canMoveObject = true;
	
	/**
	 * indicates if can select an object or not
	 */
	public static boolean canSelect = true;

	/**
	 * indicates if the camera can be moved or not
	 */
	public static boolean canMoveCamera = true;

	/**
	 * remembers the layers to show\hide
	 */
	public static boolean showLayer[];

	protected static EditorCore thisInstance;

	/**
	 * info. for the grid
	 */
	private static int widthGrid = 100;

	/**
	 * info for the grid
	 */
	private static int heightGrid = 100;

	static {
		showLayer = new boolean[numberOfLayers];
		for (int i = 0; i < numberOfLayers; ++i) {
			showLayer[i] = true;
		}
	}

	public EditorCore(int width, int height, int bpp, Container container) {
		super(width, height, bpp, container);
		thisInstance = this;
	}

	@Override public void creation() {
		DebugManager.debug = true;
		camera.setClearColor(0.3f, 0.3f, 0.3f, 0);
	}

	public void render() {
		loop();
		CommandList.render();
		drawGrid();
	}

	protected void drawGrid() {
		if (!drawGrid)
			return;
		int sx = widthGrid;
		int sy = heightGrid;
		if (sx < 10 || sy < 10)
			return;
		final int width = StaticRef.getCamera().getWidth() + sx * 2;
		final int height = StaticRef.getCamera().getHeight() + sy * 2;
		GL11.glDisable(GL11.GL_TEXTURE_2D);
		GL11.glLineWidth(2);
		// GL11.glColor3f((float) Math.random() * 0.2f,
		// (float) Math.random() * 0.2f, (float) Math.random() * 0.2f);
		OpenGLState.disableBlending();
		GL11.glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
		GL11.glBegin(GL11.GL_LINES);
		for (int x = -(int) StaticRef.getCamera().x % sx; x < width; x += sx) {
			GL11.glVertex2f(x, 0);
			GL11.glVertex2f(x, height);
		}
		for (int y = -(int) StaticRef.getCamera().y % sy; y < height; y += sy) {
			GL11.glVertex2f(0, y);
			GL11.glVertex2f(width, y);
		}

		if (StaticRef.getCamera().x <= 0
				&& StaticRef.getCamera().x + StaticRef.getCamera().getWidth() > 0) {
			GL11.glColor3f(1.0f, 0.5f, 0.5f);
			GL11.glVertex2f((int) -StaticRef.getCamera().x, 0);
			GL11.glVertex2f((int) -StaticRef.getCamera().x, height);
		}
		if (StaticRef.getCamera().y <= 0
				&& StaticRef.getCamera().y + StaticRef.getCamera().getHeight() > 0) {
			GL11.glColor3f(1.0f, 0.5f, 0.5f);
			GL11.glVertex2f(0, (int) -StaticRef.getCamera().y);
			GL11.glVertex2f(width, (int) -StaticRef.getCamera().y);
		}

		GL11.glEnd();
		/*
		 * GL11.glLineWidth(0.1f); sx /= 2; sy /= 2;
		 * GL11.glBegin(GL11.GL_LINES); for (int x = -(int)
		 * StaticRef.getCamera().x % sx; x < width; x += sx) {
		 * GL11.glVertex2f(x, 0); GL11.glVertex2f(x, height); } for (int y =
		 * -(int) StaticRef.getCamera().y % sy; y < height; y += sy) {
		 * GL11.glVertex2f(0, y); GL11.glVertex2f(width, y); } GL11.glEnd();
		 */
		OpenGLState.enableBlending();
		GL11.glEnable(GL11.GL_TEXTURE_2D);
	}

	public void loop() {
		moveObject();
		moveCamera();
	}

	public void coreRender() {
		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
		GL11.glLoadIdentity();
		assert StaticRef.layers != null;
		synchronized (StaticRef.layers) {
			// StaticRef.drawingList.render();
			for (int i = 0; i < StaticRef.layers.length; ++i) {
				if (StaticRef.layers[i] != null && showLayer[i])
					StaticRef.layers[i].render();
			}
		}
		render();
	}

	// ------------------------------
	// ------------------------------

	protected float startx, starty;

	public void moveCamera() {
		if (!canMoveCamera)
			return;
		Camera camera = StaticRef.getCamera();
		float fac = camera.getZoom2D();
		if (!Mouse.isMiddleDown()) {
			startx = Mouse.getXinWorld(); // getX() * fac +
			// StaticRef.getCamera().getx();
			starty = Mouse.getYinWorld();// getY() * fac +
			// StaticRef.getCamera().gety();

		} else {
			camera.setx(startx - Mouse.getX());
			camera.sety(starty - Mouse.getY());
		}
		if (Keyboard.isKeyReleased(Keyboard.KEY_PRIOR)) {
			camera.zoom2D(fac + 0.03f);
		} else if (Keyboard.isKeyReleased(Keyboard.KEY_NEXT)) {
			camera.zoom2D(fac - 0.03f);
		}
	}

	// ------------------------------
	// ------------------------------

	protected IPlain2D attracked;

	protected Object objSelected;

	protected IPlain2D selected;

	protected float incx, incy;

	public void moveObject() {
		if (!canMoveObject)
			return;
		if (attracked != null) {
			setSelected(attracked);
			if (Mouse.isRightDown()) { // move the object
				attracked.setXY(Mouse.getXinWorld() + incx, Mouse.getYinWorld()
						+ incy);
				return;
			} else {
				attracked = null;
			}
		}

		ArrayList<IPlain2D> list;
		if (Mouse.isLeftPressed() && canSelect) { // select the object
			list = Mouse.getOver(StaticRef.getCamera().objectsAtScreen);
			if (list == null)
				return;
			if (list.size() == 1) {
				attracked = list.get(0);
				incx = attracked.getX() - Mouse.getXinWorld();
				incy = attracked.getY() - Mouse.getYinWorld();
			} else if (list.size() > 1) {
				// complex
				ObjectEditorWrapper clickobj = new ObjectEditorWrapper(null);
				IPlain2D less = null;
				int lastlayer = Integer.MIN_VALUE;

				for (int i = 0; i < list.size(); ++i) {
					// System.out.println("trying");
					if (list.get(i) instanceof ILayer) {

						if (list.get(i) instanceof IMaskerable) {
							clickobj.obj = list.get(i);
							if (Mouse
									.<ObjectEditorWrapper> testCollision(clickobj)) {
								if (lastlayer <= clickobj.getLayer()) {
									// System.out.println("less finded");
									lastlayer = clickobj.getLayer();
									less = list.get(i);
								}
							}
						} else {// end if is IMaskerable
							if (lastlayer <= ((ILayer) list.get(i)).getLayer()) {
								// System.out.println("less finded");
								lastlayer = ((ILayer) list.get(i)).getLayer();
								less = list.get(i);
							}
						}

					}
				}// end for (search clickables objs)

				if (less != null) {
					attracked = less;
					incx = attracked.getX() - Mouse.getXinWorld();
					incy = attracked.getY() - Mouse.getYinWorld();
				}

			}
		}
	}

	class ObjectEditorWrapper implements IPlain2D, ILayer, IMaskerable {
		Object obj;

		public ObjectEditorWrapper(Object obj) {
			this.obj = obj;
		}

		public int getHeight() {
			return ((IPlain2D) obj).getHeight();
		}

		public int getWidth() {
			return ((IPlain2D) obj).getWidth();
		}

		public void setHeight(int height) {
			((IPlain2D) obj).setHeight(height);
		}

		public void setSize(int width, int height) {
			((IPlain2D) obj).setSize(width, height);
		}

		public void setWidth(int width) {
			((IPlain2D) obj).setWidth(width);
		}

		public void setX(float x) {
			((IPlain2D) obj).setX(x);
		}

		public void setXY(float x, float y) {
			((IPlain2D) obj).setXY(x, y);
		}

		public void setY(float y) {
			((IPlain2D) obj).setY(y);
		}

		public float getX() {
			return ((IPlain2D) obj).getX();
		}

		public float getXOnScreen() {
			return ((IPlain2D) obj).getXOnScreen();
		}

		public float getY() {
			return ((IPlain2D) obj).getY();
		}

		public float getYOnScreen() {
			return ((IPlain2D) obj).getYOnScreen();
		}

		public int getLayer() {
			return ((ILayer) obj).getLayer();
		}

		public ArrayList<IList> getDataLists() {
			return ((ILayer) obj).getDataLists();
		}

		public ArrayList<IList> getExtraLists() {
			return ((ILayer) obj).getExtraLists();
		}

		public ArrayList<IList> getGraphicLists() {
			return ((ILayer) obj).getGraphicLists();
		}

		public ArrayList<IList> getUsedLists() {
			return ((ILayer) obj).getUsedLists();
		}

		public void destroy() {
			((IDestroyable) obj).destroy();
		}

		public boolean isDestroyed() {
			return ((IDestroyable) obj).isDestroyed();
		}

		public Type getType() {
			return ((IType) obj).getType();
		}

		public Mask getMask() {
			return ((IMaskerable) obj).getMask();
		}

	}

	// --------------------

	int oldMenuState;

	public void setSelected(Object selected) {
		if (objSelected == selected && oldMenuState == UEditor.menuState)
			return;
		objSelected = selected;
		if (selected instanceof Plain2D) {
			this.selected = (Plain2D) selected;
		}
		if (selected != null) {
			Analyzer.removeFromLPanel();
			// Analyzer.searchStaticMethods(selected.getClass());
			Analyzer.searchMethods(selected.getClass());
		}
		oldMenuState = UEditor.menuState;
	}

	public Object getSelected() {
		return objSelected;
	}

	// --------------------
	public static EditorCore getInstance() {
		return thisInstance;
	}

	public static void setCanMoveCamera(boolean value) {
		UEditor.getNavigator().setEnabled(value);
		canMoveCamera = value;
	}

	public static void setCanMoveObjects(boolean value) {
		canMoveObject = value;
	}

	public static int getHeightGrid() {
		return heightGrid;
	}

	public static void setHeightGrid(int heightGrid) {
		if (heightGrid <= 0)
			return;
		EditorCore.heightGrid = heightGrid;
	}

	public static int getWidthGrid() {
		return widthGrid;
	}

	public static void setWidthGrid(int widthGrid) {
		if (widthGrid <= 0)
			return;
		EditorCore.widthGrid = widthGrid;
	}

	// @Method("Start Game")//
	// public static void startGame() {
	// DebugManager.debug = false;
	// }

}
